<?php

namespace Utils\Service\Common;

trait Curl
{

    protected $OPT_USER_AGENT = 'EuCurl/1.0';

    protected $OPT_TIMEOUT = 30;

    protected $proxy;

    public function __construct($proxy = null)
    {
        if ($proxy) {
            $proxy = array_merge([
                'type' => false,
                'host' => false,
                'port' => false,
                'except' => [],
                'accept' => []
            ], $proxy);
        }
        if (empty($proxy['type']) || empty($proxy['host']) || empty($proxy['port'])) {
            $proxy = null;
        }
        $this->proxy = $proxy;
    }

    public function setTimeout($timeout)
    {
        $this->OPT_TIMEOUT = max(intval($timeout), 1);
    }

    public function getTimeout()
    {
        return $this->OPT_TIMEOUT;
    }

    protected function exceptProxy($url)
    {
        if (preg_match('|^https?://(?<host>[^/]+)|', strtolower($url), $matches) === 1) {
            $host = $matches['host'];
            $excepts = $this->proxy['except'] ? $this->proxy['except'] : [];
            $accepts = $this->proxy['accept'] ? $this->proxy['accept'] : [];
            // 优先使用白名单
            return !empty($accepts) ? !in_array($host, $accepts) : in_array($host, $excepts);
        }
        return false;
    }

    // --------------------------------------------------------------------

    protected function is_assoc($arr)
    {
        return array_keys($arr) !== range(0, count($arr) - 1);
    }

    protected function formatHeaders($headers)
    {
        if (!$this->is_assoc($headers)) {
            return $headers;
        }
        return array_map(function ($value, $key) {
            return "{$key}: {$value}";
        }, $headers, array_keys($headers));
    }

    /**
     * 创建Curl实例
     */
    protected function curlInstance($url, $header = NULL)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_USERAGENT, $this->OPT_USER_AGENT);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        if (!empty($header)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $this->formatHeaders($header));
        }
        if (!empty($this->proxy) && !$this->exceptProxy($url)) {
            $proxyType = 'HTTP' == strtoupper($this->proxy['type']) ? CURLPROXY_HTTP : CURLPROXY_SOCKS5;
            curl_setopt($ch, CURLOPT_PROXYTYPE, $proxyType);
            curl_setopt($ch, CURLOPT_PROXY, $this->proxy['host']);
            curl_setopt($ch, CURLOPT_PROXYPORT, $this->proxy['port']);

        }
        curl_setopt($ch, CURLOPT_TIMEOUT, $this->OPT_TIMEOUT); // 设置curl允许执行的最长秒数
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        return $ch;
    }

    public function stream($method, $url, $body = FALSE, $header = array())
    {
        $data4Log = $body;
        if ($body && strlen($data4Log) > 1024) {
            $data4Log = '<' . strlen($data4Log) . ' bytes data>';
        } else if (empty($body)) {
            $data4Log = '<NULL>';
        }

        $ch = $this->curlInstance($url, $header);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

        $fp = fopen('stream://1', 'r+');
        curl_setopt($ch, CURLOPT_FILE, $fp);
        curl_exec($ch);
        curl_close($ch);
    }

    /**
     * curl get请求方式
     *
     * @param string url 调用API的请求地址
     * @return array
     */
    public function curlGet($url, $header = array())
    {
        return $this->curlMethod($url, 'GET', false, $header);
    }

    public function curlDelete($url, $header = array())
    {
        return $this->curlMethod($url, 'DELETE', false, $header);
    }

    protected function exec($ch)
    {
        $response = curl_exec($ch);
        $result = curl_errno($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); // 获得响应结果里的：头大小
        $responseHeader = substr($response, 0, $headerSize); // 根据头大小去获取头信息内容
        $response = substr($response, $headerSize);
        $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        curl_close($ch);
        return $response;
//		return array (
//				$result,$response,$status,$contentType
//		);
    }

    /**
     * curl delete请求方式
     *
     * @param string url 调用API的请求地址
     * @return array
     */
    public function curlMethod($url, $method, $body = FALSE, $header = array())
    {
        $data4Log = $body;
        if ($body && strlen($data4Log) > 1024) {
            $data4Log = '<' . strlen($data4Log) . ' bytes data>';
        } else if (empty($body)) {
            $data4Log = '<NULL>';
        }

        $ch = $this->curlInstance($url, $header);
        curl_setopt($ch, CURLOPT_HEADER, true); // 获取头信息
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        if ($body) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        }
        return $this->exec($ch);
    }

    /**
     * 解析返回Cookies信息，返回一个Map数组
     */
    protected function parseCookiesFromHeader($responseHeader)
    {
        preg_match_all('|Set-Cookie: (?<name>\w+)=(?<value>[^;]+)|i', $responseHeader, $results);
        $keys = $results['name'];
        $values = $results['value'];
        return array_combine($keys, $values);
    }

    /**
     * curl post请求方式
     *
     * @param string url 调用API的请求地址
     * @param string data 发送内容
     * @param array  header 发送内容类型
     * @return array
     */
    public function curlPost($url, $data, $header = array())
    {
        return $this->curlMethod($url, 'POST', $data, $header);
    }

}

